1   /*
2    * Copyright (C) 2005 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.base;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.annotations.GwtIncompatible;
21  import com.google.common.collect.ImmutableMap;
22  import com.google.common.collect.Maps;
23  import com.google.common.testing.ClassSanityTester;
24  import com.google.common.testing.EqualsTester;
25  import com.google.common.testing.NullPointerTester;
26  import com.google.common.testing.SerializableTester;
27  
28  import junit.framework.TestCase;
29  
30  import java.io.Serializable;
31  import java.util.Map;
32  
33  /**
34   * Tests for {@link Functions}.
35   *
36   * @author Mike Bostock
37   * @author Vlad Patryshev
38   */
39  @GwtCompatible(emulated = true)
40  public class FunctionsTest extends TestCase {
41  
42    public void testIdentity_same() {
43      Function<String, String> identity = Functions.identity();
44      assertNull(identity.apply(null));
45      assertSame("foo", identity.apply("foo"));
46    }
47  
48    public void testIdentity_notSame() {
49      Function<Long, Long> identity = Functions.identity();
50      assertNotSame(new Long(135135L), identity.apply(new Long(135135L)));
51    }
52  
53    @GwtIncompatible("SerializableTester")
54    public void testIdentitySerializable() {
55      checkCanReserializeSingleton(Functions.identity());
56    }
57  
58    public void testToStringFunction_apply() {
59      assertEquals("3", Functions.toStringFunction().apply(3));
60      assertEquals("hiya", Functions.toStringFunction().apply("hiya"));
61      assertEquals("I'm a string",
62          Functions.toStringFunction().apply(
63              new Object() {
64                @Override public String toString() {
65                  return "I'm a string";
66                }
67              }));
68      try {
69        Functions.toStringFunction().apply(null);
70        fail("expected NullPointerException");
71      } catch (NullPointerException e) {
72        // expected
73      }
74    }
75  
76    @GwtIncompatible("SerializableTester")
77    public void testToStringFunctionSerializable() {
78      checkCanReserializeSingleton(Functions.toStringFunction());
79    }
80  
81    @GwtIncompatible("NullPointerTester")
82    public void testNullPointerExceptions() {
83      NullPointerTester tester = new NullPointerTester();
84      tester.testAllPublicStaticMethods(Functions.class);
85    }
86  
87    public void testForMapWithoutDefault() {
88      Map<String, Integer> map = Maps.newHashMap();
89      map.put("One", 1);
90      map.put("Three", 3);
91      map.put("Null", null);
92      Function<String, Integer> function = Functions.forMap(map);
93  
94      assertEquals(1, function.apply("One").intValue());
95      assertEquals(3, function.apply("Three").intValue());
96      assertNull(function.apply("Null"));
97  
98      try {
99        function.apply("Two");
100       fail();
101     } catch (IllegalArgumentException expected) {
102     }
103 
104     new EqualsTester()
105         .addEqualityGroup(function, Functions.forMap(map))
106         .addEqualityGroup(Functions.forMap(map, 42))
107         .testEquals();
108   }
109 
110   @GwtIncompatible("SerializableTester")
111   public void testForMapWithoutDefaultSerializable() {
112     checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2)));
113   }
114 
115   public void testForMapWithDefault() {
116     Map<String, Integer> map = Maps.newHashMap();
117     map.put("One", 1);
118     map.put("Three", 3);
119     map.put("Null", null);
120     Function<String, Integer> function = Functions.forMap(map, 42);
121 
122     assertEquals(1, function.apply("One").intValue());
123     assertEquals(42, function.apply("Two").intValue());
124     assertEquals(3, function.apply("Three").intValue());
125     assertNull(function.apply("Null"));
126 
127     new EqualsTester()
128         .addEqualityGroup(function, Functions.forMap(map, 42))
129         .addEqualityGroup(Functions.forMap(map))
130         .addEqualityGroup(Functions.forMap(map, null))
131         .addEqualityGroup(Functions.forMap(map, 43))
132         .testEquals();
133   }
134 
135   @GwtIncompatible("SerializableTester")
136   public void testForMapWithDefault_includeSerializable() {
137     Map<String, Integer> map = Maps.newHashMap();
138     map.put("One", 1);
139     map.put("Three", 3);
140     Function<String, Integer> function = Functions.forMap(map, 42);
141 
142     assertEquals(1, function.apply("One").intValue());
143     assertEquals(42, function.apply("Two").intValue());
144     assertEquals(3, function.apply("Three").intValue());
145 
146     new EqualsTester()
147         .addEqualityGroup(
148             function,
149             Functions.forMap(map, 42),
150             SerializableTester.reserialize(function))
151         .addEqualityGroup(Functions.forMap(map))
152         .addEqualityGroup(Functions.forMap(map, null))
153         .addEqualityGroup(Functions.forMap(map, 43))
154         .testEquals();
155   }
156 
157   @GwtIncompatible("SerializableTester")
158   public void testForMapWithDefaultSerializable() {
159     checkCanReserialize(Functions.forMap(ImmutableMap.of(1, 2), 3));
160   }
161 
162   public void testForMapWithDefault_null() {
163     ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
164     Function<String, Integer> function = Functions.forMap(map, null);
165 
166     assertEquals((Integer) 1, function.apply("One"));
167     assertNull(function.apply("Two"));
168 
169     // check basic sanity of equals and hashCode
170     new EqualsTester()
171         .addEqualityGroup(function)
172         .addEqualityGroup(Functions.forMap(map, 1))
173         .testEquals();
174   }
175 
176   @GwtIncompatible("SerializableTester")
177   public void testForMapWithDefault_null_compareWithSerializable() {
178     ImmutableMap<String, Integer> map = ImmutableMap.of("One", 1);
179     Function<String, Integer> function = Functions.forMap(map, null);
180 
181     assertEquals((Integer) 1, function.apply("One"));
182     assertNull(function.apply("Two"));
183 
184     // check basic sanity of equals and hashCode
185     new EqualsTester()
186         .addEqualityGroup(function, SerializableTester.reserialize(function))
187         .addEqualityGroup(Functions.forMap(map, 1))
188         .testEquals();
189   }
190 
191   public void testForMapWildCardWithDefault() {
192     Map<String, Integer> map = Maps.newHashMap();
193     map.put("One", 1);
194     map.put("Three", 3);
195     Number number = Double.valueOf(42);
196     Function<String, Number> function = Functions.forMap(map, number);
197 
198     assertEquals(1, function.apply("One").intValue());
199     assertEquals(number, function.apply("Two"));
200     assertEquals(3L, function.apply("Three").longValue());
201   }
202 
203   public void testComposition() {
204     Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
205     mJapaneseToInteger.put("Ichi", 1);
206     mJapaneseToInteger.put("Ni", 2);
207     mJapaneseToInteger.put("San", 3);
208     Function<String, Integer> japaneseToInteger =
209         Functions.forMap(mJapaneseToInteger);
210 
211     Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
212     mIntegerToSpanish.put(1, "Uno");
213     mIntegerToSpanish.put(3, "Tres");
214     mIntegerToSpanish.put(4, "Cuatro");
215     Function<Integer, String> integerToSpanish =
216         Functions.forMap(mIntegerToSpanish);
217 
218     Function<String, String> japaneseToSpanish =
219         Functions.compose(integerToSpanish, japaneseToInteger);
220 
221     assertEquals("Uno", japaneseToSpanish.apply("Ichi"));
222     try {
223       japaneseToSpanish.apply("Ni");
224       fail();
225     } catch (IllegalArgumentException e) {
226     }
227     assertEquals("Tres", japaneseToSpanish.apply("San"));
228     try {
229       japaneseToSpanish.apply("Shi");
230       fail();
231     } catch (IllegalArgumentException e) {
232     }
233 
234     new EqualsTester()
235         .addEqualityGroup(
236             japaneseToSpanish,
237             Functions.compose(integerToSpanish, japaneseToInteger))
238         .addEqualityGroup(japaneseToInteger)
239         .addEqualityGroup(integerToSpanish)
240         .addEqualityGroup(
241             Functions.compose(japaneseToInteger, integerToSpanish))
242         .testEquals();
243   }
244 
245   @GwtIncompatible("SerializableTester")
246   public void testComposition_includeReserializabled() {
247     Map<String, Integer> mJapaneseToInteger = Maps.newHashMap();
248     mJapaneseToInteger.put("Ichi", 1);
249     mJapaneseToInteger.put("Ni", 2);
250     mJapaneseToInteger.put("San", 3);
251     Function<String, Integer> japaneseToInteger =
252         Functions.forMap(mJapaneseToInteger);
253 
254     Map<Integer, String> mIntegerToSpanish = Maps.newHashMap();
255     mIntegerToSpanish.put(1, "Uno");
256     mIntegerToSpanish.put(3, "Tres");
257     mIntegerToSpanish.put(4, "Cuatro");
258     Function<Integer, String> integerToSpanish =
259         Functions.forMap(mIntegerToSpanish);
260 
261     Function<String, String> japaneseToSpanish =
262         Functions.compose(integerToSpanish, japaneseToInteger);
263 
264     new EqualsTester()
265         .addEqualityGroup(
266             japaneseToSpanish,
267             Functions.compose(integerToSpanish, japaneseToInteger),
268             SerializableTester.reserialize(japaneseToSpanish))
269         .addEqualityGroup(japaneseToInteger)
270         .addEqualityGroup(integerToSpanish)
271         .addEqualityGroup(
272             Functions.compose(japaneseToInteger, integerToSpanish))
273         .testEquals();
274   }
275 
276   public void testCompositionWildcard() {
277     Map<String, Integer> mapJapaneseToInteger = Maps.newHashMap();
278     Function<String, Integer> japaneseToInteger =
279         Functions.forMap(mapJapaneseToInteger);
280 
281     Function<Object, String> numberToSpanish = Functions.constant("Yo no se");
282 
283     Function<String, String> japaneseToSpanish =
284         Functions.compose(numberToSpanish, japaneseToInteger);
285   }
286 
287   private static class HashCodeFunction implements Function<Object, Integer> {
288     @Override
289     public Integer apply(Object o) {
290       return (o == null) ? 0 : o.hashCode();
291     }
292   }
293 
294   public void testComposeOfFunctionsIsAssociative() {
295     Map<Float, String> m = ImmutableMap.of(
296         4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
297     Function<? super Integer, Boolean> h = Functions.constant(Boolean.TRUE);
298     Function<? super String, Integer> g = new HashCodeFunction();
299     Function<Float, String> f = Functions.forMap(m, "F");
300 
301     Function<Float, Boolean> c1 = Functions.compose(Functions.compose(h, g), f);
302     Function<Float, Boolean> c2 = Functions.compose(h, Functions.compose(g, f));
303 
304     // Might be nice (eventually) to have:
305     //     assertEquals(c1, c2);
306 
307     // But for now, settle for this:
308     assertEquals(c1.hashCode(), c2.hashCode());
309 
310     assertEquals(c1.apply(1.0f), c2.apply(1.0f));
311     assertEquals(c1.apply(5.0f), c2.apply(5.0f));
312   }
313 
314   public void testComposeOfPredicateAndFunctionIsAssociative() {
315     Map<Float, String> m = ImmutableMap.of(
316         4.0f, "A", 3.0f, "B", 2.0f, "C", 1.0f, "D");
317     Predicate<? super Integer> h = Predicates.equalTo(42);
318     Function<? super String, Integer> g = new HashCodeFunction();
319     Function<Float, String> f = Functions.forMap(m, "F");
320 
321     Predicate<Float> p1 = Predicates.compose(Predicates.compose(h, g), f);
322     Predicate<Float> p2 = Predicates.compose(h, Functions.compose(g, f));
323 
324     // Might be nice (eventually) to have:
325     //     assertEquals(p1, p2);
326 
327     // But for now, settle for this:
328     assertEquals(p1.hashCode(), p2.hashCode());
329 
330     assertEquals(p1.apply(1.0f), p2.apply(1.0f));
331     assertEquals(p1.apply(5.0f), p2.apply(5.0f));
332   }
333 
334   public void testForPredicate() {
335     Function<Object, Boolean> alwaysTrue =
336         Functions.forPredicate(Predicates.alwaysTrue());
337     Function<Object, Boolean> alwaysFalse =
338         Functions.forPredicate(Predicates.alwaysFalse());
339 
340     assertTrue(alwaysTrue.apply(0));
341     assertFalse(alwaysFalse.apply(0));
342 
343     new EqualsTester()
344         .addEqualityGroup(
345             alwaysTrue, Functions.forPredicate(Predicates.alwaysTrue()))
346         .addEqualityGroup(alwaysFalse)
347         .addEqualityGroup(Functions.identity())
348         .testEquals();
349   }
350 
351   @GwtIncompatible("SerializableTester")
352   public void testForPredicateSerializable() {
353     checkCanReserialize(Functions.forPredicate(Predicates.equalTo(5)));
354   }
355 
356   public void testConstant() {
357     Function<Object, Object> f = Functions.<Object>constant("correct");
358     assertEquals("correct", f.apply(new Object()));
359     assertEquals("correct", f.apply(null));
360 
361     Function<Object, String> g = Functions.constant(null);
362     assertEquals(null, g.apply(2));
363     assertEquals(null, g.apply(null));
364 
365     new EqualsTester()
366         .addEqualityGroup(f, Functions.constant("correct"))
367         .addEqualityGroup(Functions.constant("incorrect"))
368         .addEqualityGroup(Functions.toStringFunction())
369         .addEqualityGroup(g)
370         .testEquals();
371 
372     new EqualsTester()
373         .addEqualityGroup(g, Functions.constant(null))
374         .addEqualityGroup(Functions.constant("incorrect"))
375         .addEqualityGroup(Functions.toStringFunction())
376         .addEqualityGroup(f)
377         .testEquals();
378   }
379 
380   @GwtIncompatible("SerializableTester")
381   public void testConstantSerializable() {
382     checkCanReserialize(Functions.constant(5));
383   }
384 
385   private static class CountingSupplier
386       implements Supplier<Integer>, Serializable {
387 
388     private static final long serialVersionUID = 0;
389 
390     private int value;
391 
392     @Override
393     public Integer get() {
394       return ++value;
395     }
396 
397     @Override
398     public boolean equals(Object obj) {
399       if (obj instanceof CountingSupplier) {
400         return this.value == ((CountingSupplier) obj).value;
401       }
402       return false;
403     }
404 
405     @Override
406     public int hashCode() {
407       return value;
408     }
409   }
410 
411   public void testForSupplier() {
412     Supplier<Integer> supplier = new CountingSupplier();
413     Function<Object, Integer> function = Functions.forSupplier(supplier);
414 
415     assertEquals(1, (int) function.apply(null));
416     assertEquals(2, (int) function.apply("foo"));
417 
418     new EqualsTester()
419         .addEqualityGroup(function, Functions.forSupplier(supplier))
420         .addEqualityGroup(Functions.forSupplier(new CountingSupplier()))
421         .addEqualityGroup(Functions.forSupplier(Suppliers.ofInstance(12)))
422         .addEqualityGroup(Functions.toStringFunction())
423         .testEquals();
424   }
425 
426   @GwtIncompatible("SerializableTester")
427   public void testForSupplierSerializable() {
428     checkCanReserialize(Functions.forSupplier(new CountingSupplier()));
429   }
430 
431   @GwtIncompatible("reflection")
432   public void testNulls() throws Exception {
433     new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testNulls();
434   }
435 
436   @GwtIncompatible("reflection")
437   public void testEqualsAndSerializable() throws Exception {
438     new ClassSanityTester().forAllPublicStaticMethods(Functions.class).testEqualsAndSerializable();
439   }
440 
441   @GwtIncompatible("SerializableTester")
442   private static <Y> void checkCanReserialize(Function<? super Integer, Y> f) {
443     Function<? super Integer, Y> g = SerializableTester.reserializeAndAssert(f);
444     for (int i = 1; i < 5; i++) {
445       // convoluted way to check that the same result happens from each
446       Y expected = null;
447       try {
448         expected = f.apply(i);
449       } catch (IllegalArgumentException e) {
450         try {
451           g.apply(i);
452           fail();
453         } catch (IllegalArgumentException ok) {
454           continue;
455         }
456       }
457       assertEquals(expected, g.apply(i));
458     }
459   }
460 
461   @GwtIncompatible("SerializableTester")
462   private static <Y> void checkCanReserializeSingleton(Function<? super String, Y> f) {
463     Function<? super String, Y> g = SerializableTester.reserializeAndAssert(f);
464     assertSame(f, g);
465     for (Integer i = 1; i < 5; i++) {
466       assertEquals(f.apply(i.toString()), g.apply(i.toString()));
467     }
468   }
469 
470 }